package ph.com.gs3.formalistics.service.services;

import java.util.List;

import ph.com.gs3.formalistics.global.utilities.logging.FLLogger;
import ph.com.gs3.formalistics.global.utilities.services.ServiceEventNotifierUtility;
import ph.com.gs3.formalistics.model.communicators.FormCommunicatorModule;
import ph.com.gs3.formalistics.model.communicators.HttpCommunicator;
import ph.com.gs3.formalistics.model.dao.FormsDAO;
import ph.com.gs3.formalistics.model.dao.UserAccountsDAO;
import ph.com.gs3.formalistics.model.valueobjects.business.User;
import ph.com.gs3.formalistics.model.valueobjects.business.form.Form;
import ph.com.gs3.formalistics.presenter.MainActivity;
import ph.com.gs3.formalistics.service.managers.FormManager;
import ph.com.gs3.formalistics.service.managers.FormManager.FormsUpdateFailedException;
import android.app.IntentService;
import android.content.Intent;
import android.os.Bundle;

/**
 * Back end service.
 * 
 * Manages updating of forms in this device. Updating will start as soon as startService
 * is invoked.
 * 
 * The intent used to start this service must include the current server as extra using
 * the key EXTRA_SERVER.
 * 
 * This service has 3 broadcast actions, ACTION_ON_UPDATE_STARTED, ACTION_ON_UPDATE_DONE,
 * and ACTION_ON_UPDATE_ERROR.
 * 
 * @author Ervinne Sodusta
 */
public class FormsUpdateService extends IntentService {

	public static final String TAG = FormsUpdateService.class.getSimpleName();

	public static final String NAME = FormsUpdateService.class.getName();

	public static final String ACTION_ON_UPDATE_STARTED = NAME + "_update_started";
	public static final String ACTION_ON_UPDATE_DONE = NAME + "_update_done";
	public static final String ACTION_ON_UPDATE_ERROR = NAME + "_update_error";

	// incoming extra(s)
	public static final String EXTRA_CURRENT_USER = "current_user";
	// public static final String EXTRA_SERVER = "server";

	// outgoing extra(s)
	public static final String EXTRA_FAILURE_EXCEPTION = "failure_exception";

	private User currentUser;
	private FormManager formManager;

	public FormsUpdateService() {
		super(TAG);

	}

	@Override
	protected void onHandleIntent(Intent intent) {

		currentUser = (User) intent.getExtras().getSerializable(EXTRA_CURRENT_USER);

		// notify
		Bundle notificationExtras = new Bundle();
		notificationExtras.putSerializable(MainActivity.EXTRA_LOGGED_IN_USER, currentUser);

		ServiceEventNotifierUtility.getDefaultInstance().displayNotificationWithProgress(this,
		        ServiceEventNotifierUtility.NOTIFICATION_ID_PRIMARY, "Syncing forms", 0, 0, true,
		        notificationExtras);

		String server = currentUser.getAccountServer();
		initializeFormManager(server);

		try {
			broadcastFormsUpdateStarted();
			List<Form> updatedForms = formManager.updateForms();

			ServiceEventNotifierUtility.getDefaultInstance().dismissPrimaryNotification(this);

			broadcastFormsUpdatedMessage(updatedForms);

		} catch (FormsUpdateFailedException e) {

			ServiceEventNotifierUtility.getDefaultInstance().dismissPrimaryNotification(this);

			broadcastFormsUpdateFailedException(e);
		}

		stopSelf();

	}

	private void initializeFormManager(String server) {

		UserAccountsDAO userAccountsDAO = new UserAccountsDAO(getApplicationContext());
		FormsDAO formsDAO = new FormsDAO(getApplicationContext());
		FormCommunicatorModule formCommModule = new FormCommunicatorModule(new HttpCommunicator(),
		        server);

		formManager = new FormManager(userAccountsDAO, formsDAO, formCommModule);

	}

	// ========================================================================
	// {{ Broadcaster Methods

	private void broadcastFormsUpdateStarted() {

		Intent broadcastIntent = new Intent();
		broadcastIntent.setAction(ACTION_ON_UPDATE_STARTED);
		broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
		sendBroadcast(broadcastIntent);

	}

	private void broadcastFormsUpdatedMessage(List<Form> updatedForms) {

		Intent broadcastIntent = new Intent();
		broadcastIntent.setAction(ACTION_ON_UPDATE_DONE);
		broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);

		FLLogger.d(TAG, updatedForms.size() + " updated forms.");

		sendBroadcast(broadcastIntent);

	}

	private void broadcastFormsUpdateFailedException(Exception e) {

		Intent broadcastIntent = new Intent();
		broadcastIntent.setAction(ACTION_ON_UPDATE_ERROR);
		broadcastIntent.setAction(Intent.CATEGORY_DEFAULT);

		broadcastIntent.putExtra(EXTRA_FAILURE_EXCEPTION, e);

		sendBroadcast(broadcastIntent);

	}

	// }}

}
